package com.navinfo.tripanalysis.common.vehicle;

import com.github.benmanes.caffeine.cache.Caffeine;
import com.github.benmanes.caffeine.cache.LoadingCache;
import com.navinfo.tripanalysis.common.util.GsonUtils;
import com.navinfo.tripanalysis.common.util.RedisUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 通过本地缓存或Redis获取车辆信息<br/>
 * 后台有kettle抽取车辆信息到Redis中，车辆参数信息全部放入Redis中，从Redis中读取
 * @author 沈东生
 */
public class VehicleInfoServiceImpl implements VehicleInfoService {
    private static Logger logger = LoggerFactory.getLogger(VehicleInfoServiceImpl.class);

    /**
     * Redis缓存
     */
    private RedisUtils redisCache;

    /**
     * 本地缓存
     */
    private LoadingCache<Long, VehicleInfo> localCache;

    /**
     * redis中存储的key前缀
     */
    public static final String KEY_PREFIX = "vehicleInfo";


    @Override
    public void init(Map map) throws Exception {
        RedisUtils.buildInstance(map);
        redisCache = RedisUtils.getInstance();
        localCache = Caffeine.newBuilder()
                .refreshAfterWrite(Integer.parseInt(String.valueOf(map.get("vehicleInfo.Syn.Time"))), TimeUnit.HOURS)
                .initialCapacity(Integer.parseInt(String.valueOf(map.get("vehicleInfo.initialCapacity"))))
                .build(key -> getVehicleInfo(key));

    }

    @Override
    public VehicleInfo get(long terminalId) {
        VehicleInfo vehicleInfo = null;
        try {
            vehicleInfo = localCache.get(terminalId);
        } catch (Exception e) {
            logger.error("获取车辆信息错误：" + terminalId, e);
        }
        return vehicleInfo;
    }

    @Override
    public void put(long terminalId, String subKey, Object value) {
        String redisKey = getKey(terminalId);
        redisCache.setHashValue(redisKey,subKey,GsonUtils.gsonString(value));
    }

    @Override
    public void reload(long terminalId){
        //从redis中获取最新的信息
        localCache.invalidate(terminalId);
    }

    /**
     * 查询redis中车辆信息，如果查询到将信息保存到本地缓存中
     * 设置最后更新时间
     * @param terminalId
     */
    private VehicleInfo getVehicleInfo(long terminalId) {
        String redisKey = getKey(terminalId);
        VehicleInfo result = null;
        try {
            Map<String, String> map = redisCache.getHashValueAll(redisKey);
            if(map == null || map.size() == 0){
                result = new VehicleInfo();
                logger.info("获取车辆信息失败，放入一个空对象：" + terminalId);
                return result;
            }
            String jsonStr = GsonUtils.gsonString(map).replace("\"[", "[")
                    .replace("]\"", "]")
                    .replace("\"{", "{")
                    .replace("}\"", "}")
                    .replace("\\", "");

            if (StringUtils.isNotEmpty(jsonStr)) {
                result = GsonUtils.gsonToBean(jsonStr, VehicleInfo.class);
                // redis的value没有存terminalId
                // 所以这里需要设置一下
                result.setTerminalId(terminalId);
                result.setUpdateTime(System.currentTimeMillis());
                logger.info("获取车辆信息成功：" + terminalId);
            }

            if (result == null) {
                result = new VehicleInfo();
                logger.info("获取车辆信息失败，放入一个空对象：" + terminalId);
            }
        } catch (Exception e){
            e.printStackTrace();
            result = new VehicleInfo();
            logger.info("解析车辆信息失败，放入一个空对象：" + terminalId);
        }
        return result;
    }


    /**
     * 获取Redis中缓存的key
     * @param terminalId 终端编号
     */
    String getKey(long terminalId) {
        return String.format("%s_%d", KEY_PREFIX, terminalId);
    }


}
